
`default_nettype wire


//

`ifdef ALT_MEM_PHY_DEFINES
`else
`include "alt_mem_phy_defines.v"
`endif

//
module ddr2_phy_alt_mem_phy_clk_reset (
                               pll_ref_clk,
                               global_reset_n,
                               soft_reset_n,
                               seq_rdp_reset_req_n,

                               ac_clk_2x,
                               measure_clk_2x,
                               mem_clk_2x,
                               mem_clk,
                               mem_clk_n,
                               ctl_clk,
                               resync_clk_2x,
                               cs_n_clk_2x,
                               write_clk_2x,
                               half_rate_clk,

                               reset_ac_clk_2x_n,
                               reset_measure_clk_2x_n,
                               reset_mem_clk_2x_n,
                               reset_phy_clk_1x_n,
                               reset_resync_clk_2x_n,
                               reset_write_clk_2x_n,
                               reset_cs_n_clk_2x_n,
                               reset_rdp_phy_clk_1x_n,
                               mem_reset_n,

                               reset_request_n, // new output

                               phs_shft_busy,

                               seq_pll_inc_dec_n,
                               seq_pll_select,
                               seq_pll_start_reconfig,

                               mimic_data_2x,

                               seq_clk_disable,
                               ctrl_clk_disable

                              ) /* synthesis altera_attribute="SUPPRESS_DA_RULE_INTERNAL=\"R101,C104\"" */;

// Note the peculiar ranging below is necessary to use a generated CASE statement
// later in the code :
parameter       AC_PHASE                     =      "MEM_CLK";
parameter       CLOCK_INDEX_WIDTH            =              3;
parameter [0:0] CAPTURE_MIMIC_PATH           =              0;
parameter [0:0] DDR_MIMIC_PATH_EN            =              1;
parameter [0:0] DEDICATED_MEMORY_CLK_EN      =              0;
parameter       DLL_EXPORT_IMPORT            =         "NONE";
parameter       DWIDTH_RATIO                 =              4;
parameter       LOCAL_IF_CLK_PS              =           4000;
parameter       MEM_IF_CLK_PAIR_COUNT        =              3;
parameter       MEM_IF_CLK_PS                =           4000;
parameter       MEM_IF_CS_WIDTH              =              2;
parameter       MEM_IF_DQ_PER_DQS            =              8;
parameter       MEM_IF_DQS_WIDTH             =              8;
parameter       MEM_IF_DWIDTH                =             64;
parameter       MIF_FILENAME                 =      "PLL.MIF";
parameter       PLL_EXPORT_IMPORT            =         "NONE";
parameter       PLL_REF_CLK_PS               =           4000;
parameter       PLL_TYPE                     =     "ENHANCED";
parameter       SPEED_GRADE                  =           "C3";
parameter       DLL_DELAY_BUFFER_MODE        =         "HIGH";
parameter       DLL_DELAY_CHAIN_LENGTH       =             10;
parameter       DQS_OUT_MODE                 = "DELAY_CHAIN2";
parameter       DQS_PHASE                    =             72;
parameter       SCAN_CLK_DIVIDE_BY           =              2;
parameter       USE_MEM_CLK_FOR_ADDR_CMD_CLK =              1;
parameter DO_CALIB;
// Clock/reset inputs :
input  wire                                                               global_reset_n;
input  wire                                                               pll_ref_clk;
input  wire                                                               soft_reset_n;
input  wire                                                               seq_rdp_reset_req_n;

// Clock/reset outputs :
(* altera_attribute = "-name global_signal   global_clock" *) output wire ac_clk_2x;
(* altera_attribute = "-name global_signal regional_clock" *) output wire measure_clk_2x;
(* altera_attribute = "-name global_signal   global_clock" *) output wire mem_clk_2x;
inout wire [MEM_IF_CLK_PAIR_COUNT - 1 : 0]                                mem_clk;
inout wire [MEM_IF_CLK_PAIR_COUNT - 1 : 0]                                mem_clk_n;
(* altera_attribute = "-name global_signal   global_clock" *) output wire ctl_clk;
(* altera_attribute = "-name global_signal regional_clock" *) output wire resync_clk_2x;
(* altera_attribute = "-name global_signal   global_clock" *) output wire cs_n_clk_2x;
(* altera_attribute = "-name global_signal   global_clock" *) output wire write_clk_2x;
output wire                                                               half_rate_clk;

output wire                                                               reset_ac_clk_2x_n;
output wire                                                               reset_measure_clk_2x_n;
output wire                                                               reset_mem_clk_2x_n;
output  reg                                                               reset_phy_clk_1x_n;
output wire                                                               reset_resync_clk_2x_n;
output wire                                                               reset_write_clk_2x_n;
output wire                                                               reset_cs_n_clk_2x_n;
output wire                                                               reset_rdp_phy_clk_1x_n;
output wire                                                               mem_reset_n;

// This is the PLL locked signal :
output wire                                                               reset_request_n;

// Misc I/O :
output reg                                                                phs_shft_busy;

input  wire                                                               seq_pll_inc_dec_n;
input  wire [CLOCK_INDEX_WIDTH - 1 : 0 ]                                  seq_pll_select;
input  wire                                                               seq_pll_start_reconfig;

output wire                                                               mimic_data_2x;

input wire                                                                seq_clk_disable;
input wire [MEM_IF_CLK_PAIR_COUNT - 1 : 0]                                ctrl_clk_disable;



(*preserve*) reg                                                          seq_pll_start_reconfig_ams;
(*preserve*) reg                                                          seq_pll_start_reconfig_r;
(*preserve*) reg                                                          seq_pll_start_reconfig_2r;
(*preserve*) reg                                                          seq_pll_start_reconfig_3r;

wire                                                                      pll_scanclk;
wire                                                                      pll_scanread;
wire                                                                      pll_scanwrite;
wire                                                                      pll_scandata;
wire                                                                      pll_scandone;
wire                                                                      pll_scandataout;

reg                                                                       pll_new_dir;
reg [2:0]                                                                 pll_new_phase;
wire                                                                      pll_phase_auto_calibrate_pulse;

reg [`CLK_PLL_RECONFIG_FSM_WIDTH-1:0]                                     pll_reconfig_state;

reg                                                                       pll_reconfig_initialised;
reg [CLOCK_INDEX_WIDTH - 1 : 0 ]                                          pll_current_phase;
reg                                                                       pll_current_dir;

reg [`CLK_PLL_RECONFIG_FSM_WIDTH-1:0]                                     next_pll_reconfig_state;

reg                                                                       next_pll_reconfig_initialised;
reg [CLOCK_INDEX_WIDTH - 1 : 0 ]                                          next_pll_current_phase;
reg                                                                       next_pll_current_dir;

(*preserve*) reg                                                          pll_reprogram_request_pulse;   // 1 scan clk cycle long
(*preserve*) reg                                                          pll_reprogram_request_pulse_r;
(*preserve*) reg                                                          pll_reprogram_request_pulse_2r;
wire                                                                      pll_reprogram_request_long_pulse; // 3 scan clk cycles long
(*preserve*) reg                                                          pll_reprogram_request;

wire                                                                      pll_reconfig_busy;
reg                                                                       pll_reconfig;
reg                                                                       pll_reconfig_write_param;
reg [3:0]                                                                 pll_reconfig_counter_type;
reg [8:0]                                                                 pll_reconfig_data_in;

wire                                                                      pll_locked;


wire                                                                      phy_internal_reset_n;
wire                                                                      pll_reset;

(*preserve*) reg                                                          global_pre_clear;
wire                                                                      global_or_soft_reset_n;

(*preserve*) reg                                                          clk_div_reset_ams_n   = 1'b0;
(*preserve*) reg                                                          clk_div_reset_ams_n_r = 1'b0;

(*preserve*) reg                                                          pll_reconfig_reset_ams_n   = 1'b0;
(*preserve*) reg                                                          pll_reconfig_reset_ams_n_r = 1'b0;

(*preserve*) reg                                                          reset_master_ams;

wire [MEM_IF_CLK_PAIR_COUNT - 1 : 0]                                      mimic_data_2x_internal;

// Create the scan clock.  This is a divided-down version of the PLL reference clock.
// The scan chain will have an Fmax of around 100MHz, and so initially the scan clock is
// created by a divide-by 4 circuit to allow plenty of margin with the expected reference
// clock frequency of 100MHz.  This may be changed via the parameter.

reg [2:0]                                                                 divider  = 3'h0;
(*preserve*) reg                                                          scan_clk = 1'b0;


(*preserve*) reg                                                          global_reset_ams_n   = 1'b0;
(*preserve*) reg                                                          global_reset_ams_n_r = 1'b0;


wire                                                                      pll_phase_done;

(*preserve*) reg [2:0]                                                    seq_pll_start_reconfig_ccd_pipe;

(*preserve*) reg                                                          seq_pll_inc_dec_ccd;
(*preserve*) reg [CLOCK_INDEX_WIDTH - 1 : 0]                              seq_pll_select_ccd ;

wire                                                                      pll_reconfig_reset_n;

wire                                                                      clk_divider_reset_n;


// Output the PLL locked signal to be used as a reset_request_n - IE. reset when the PLL loses
// lock :
assign reset_request_n = pll_locked;



// Reset the scanclk clock divider if we either have a global_reset or the PLL loses lock
assign pll_reconfig_reset_n = global_reset_n && pll_locked;


// Clock divider circuit reset generation.
always @(posedge ctl_clk or negedge pll_reconfig_reset_n)
begin

    if (pll_reconfig_reset_n == 1'b0)
    begin
        clk_div_reset_ams_n   <= 1'b0;
        clk_div_reset_ams_n_r <= 1'b0;
    end

    else
    begin
        clk_div_reset_ams_n   <= 1'b1;
        clk_div_reset_ams_n_r <= clk_div_reset_ams_n;
    end

end

// PLL reconfig and synchronisation circuit reset generation.
always @(posedge scan_clk or negedge pll_reconfig_reset_n)
begin

    if (pll_reconfig_reset_n == 1'b0)
    begin
        pll_reconfig_reset_ams_n   <= 1'b0;
        pll_reconfig_reset_ams_n_r <= 1'b0;
    end

    else
    begin
        pll_reconfig_reset_ams_n   <= 1'b1;
        pll_reconfig_reset_ams_n_r <= pll_reconfig_reset_ams_n;
    end

end

// Create the scan clock.  Used for PLL reconfiguring in this block.

// Clock divider reset is the direct output of the AMS flops :
assign clk_divider_reset_n = clk_div_reset_ams_n_r;

generate


    if (SCAN_CLK_DIVIDE_BY == 1)
    begin : no_scan_clk_divider

        always @(ctl_clk)
        begin
            scan_clk = ctl_clk;
        end

    end

    else
    begin : gen_scan_clk

        always @(posedge ctl_clk or negedge clk_divider_reset_n)
        begin

            if (clk_divider_reset_n == 1'b0)
            begin
                scan_clk  <= 1'b0;
                divider   <= 3'h0;
            end

            else
            begin

                // This method of clock division does not require "divider" to be used
                // as an intermediate clock:
                if (divider == (SCAN_CLK_DIVIDE_BY / 2 - 1))
                begin
                    scan_clk <= ~scan_clk; // Toggle
                    divider  <= 3'h0;
                end

                else
                begin
                    scan_clk <= scan_clk; // Do not toggle
                    divider  <= divider + 3'h1;
                end

            end

        end

    end

endgenerate







// Metastable-harden seq_pll_start_reconfig signal (from the phy clock domain). NB:
// by double-clocking this signal, it is not necessary to double-clock the
// seq_pll_inc_dec_n and seq_pll_select signals - since they will only get
// used on a positive edge of the metastable-hardened seq_pll_start_reconfig signal (so
// should be stable by that point).


// Rising-edge detect to generate a single phase shift step
assign pll_phase_auto_calibrate_pulse = ~seq_pll_start_reconfig_3r && seq_pll_start_reconfig_2r;

// extend the phase shift request pulse to be 3 scan clk cycles long.
assign pll_reprogram_request_long_pulse = pll_reprogram_request_pulse || pll_reprogram_request_pulse_r || pll_reprogram_request_pulse_2r;





// Gate the soft reset input (from SOPC builder for example) with the PLL
// locked signal :
assign global_or_soft_reset_n  = soft_reset_n && global_reset_n;

// Create the PHY internal reset signal :
assign phy_internal_reset_n = pll_locked && global_or_soft_reset_n;

// The PLL resets only on a global reset :
assign pll_reset = !global_reset_n;


generate

    if (DO_CALIB == 1) begin


        always @(posedge ctl_clk or negedge reset_phy_clk_1x_n)
        begin

            if (reset_phy_clk_1x_n == 1'b0)
            begin
                seq_pll_inc_dec_ccd             <= 1'b0;
                seq_pll_select_ccd              <= {CLOCK_INDEX_WIDTH{1'b0}};
                seq_pll_start_reconfig_ccd_pipe <= 3'b000;
            end

            // Generate 'ccd' Cross Clock Domain signals :
            else
            begin

                seq_pll_start_reconfig_ccd_pipe <= {seq_pll_start_reconfig_ccd_pipe[1:0], seq_pll_start_reconfig};

                if (seq_pll_start_reconfig == 1'b1 && seq_pll_start_reconfig_ccd_pipe[0] == 1'b0)
                begin
                    seq_pll_inc_dec_ccd <= seq_pll_inc_dec_n;
                    seq_pll_select_ccd  <= seq_pll_select;
                end

            end

        end

        always @(posedge scan_clk or negedge pll_reconfig_reset_ams_n_r)
        begin

            if (pll_reconfig_reset_ams_n_r == 1'b0)
            begin
                seq_pll_start_reconfig_ams     <= 1'b0;
                seq_pll_start_reconfig_r       <= 1'b0;
                seq_pll_start_reconfig_2r      <= 1'b0;
                seq_pll_start_reconfig_3r      <= 1'b0;

                pll_reprogram_request_pulse    <= 1'b0;
                pll_reprogram_request_pulse_r  <= 1'b0;
                pll_reprogram_request_pulse_2r <= 1'b0;
                pll_reprogram_request          <= 1'b0;
            end

            else
            begin
                seq_pll_start_reconfig_ams     <= seq_pll_start_reconfig_ccd_pipe[2];
                seq_pll_start_reconfig_r       <= seq_pll_start_reconfig_ams;
                seq_pll_start_reconfig_2r      <= seq_pll_start_reconfig_r;
                seq_pll_start_reconfig_3r      <= seq_pll_start_reconfig_2r;

                pll_reprogram_request_pulse    <= pll_phase_auto_calibrate_pulse;
                pll_reprogram_request_pulse_r  <= pll_reprogram_request_pulse;
                pll_reprogram_request_pulse_2r <= pll_reprogram_request_pulse_r;
                pll_reprogram_request          <= pll_reprogram_request_long_pulse;

            end

        end


        initial begin
            $display("fdsa 2 DO_CALIB:%d",DO_CALIB);
        end

        // Register the Phase step settings
        always @(posedge scan_clk or negedge pll_reconfig_reset_ams_n_r)
        begin
            if (pll_reconfig_reset_ams_n_r == 1'b0)
            begin
                pll_new_dir   <= 1'b0;
                pll_new_phase <= 3'h0; // CIII PLL has 3bit phase select
            end

            else
            begin

                if (pll_phase_auto_calibrate_pulse)
                begin
                    pll_new_dir   <= seq_pll_inc_dec_ccd;
                    pll_new_phase <= (seq_pll_select_ccd == 3'b101 && DO_CALIB==1) ? 3'b101 : 3'b111; // legal code;  
                end

            end
        end



        // generate the busy signal - just the inverse of the done o/p from the pll OR'd with the reprogram request (in case the done o/p is missed).
        always @(posedge scan_clk or negedge pll_reconfig_reset_ams_n_r)
        begin

            if (pll_reconfig_reset_ams_n_r == 1'b0)
                phs_shft_busy <= 1'b0;

            else
                phs_shft_busy <= pll_reprogram_request || ~pll_phase_done;

        end


        altsource_probe #(.enable_metastability("NO"),.instance_id("CALI"),.probe_width(16),.sld_auto_instance_index("YES"),.sld_instance_index(1),.source_initial_value(" 0"),.source_width(16))  (.probe(cnt0),.source());

        reg [15:0] cnt0;
        reg pll_reprogram_request_old;
        // generate the busy signal - just the inverse of the done o/p from the pll OR'd with the reprogram request (in case the done o/p is missed).
        always @(posedge scan_clk or negedge pll_reconfig_reset_ams_n_r) begin
            if (pll_reconfig_reset_ams_n_r == 1'b0)begin
                cnt0 <= 0;
            end else begin
                pll_reprogram_request_old <= pll_reprogram_request;
                if(pll_reprogram_request && !pll_reprogram_request_old)begin
                //5 6

                if(pll_new_phase == 5)begin
                    if(pll_new_dir)begin
                    cnt0 <= cnt0 + 1'b1;
                    end else begin
                    cnt0 <= cnt0 - 1'b1;
                    end
                end


                end
            end
        end

    end

endgenerate



generate

    begin


        //
        ddr2_phy_alt_mem_phy_pll #(
            .DO_CALIB(DO_CALIB)
        ) pll(
                    .areset(pll_reset),
            .inclk0(pll_ref_clk),
            .phasecounterselect(pll_new_phase),
            .phasestep(pll_reprogram_request && DO_CALIB==1),
            .phaseupdown(pll_new_dir),
            .scanclk(scan_clk),
            .c0(half_rate_clk),
            .c1(mem_clk_2x),
            .c2(write_clk_2x),
            .c3(resync_clk_2x),
            .c4(measure_clk_2x),
            .locked(pll_locked),
            .phasedone(pll_phase_done)
        );

        // NB. ctl_clk is now full-rate, despite the "1x" naming convention :
        assign ctl_clk = mem_clk_2x;

    end

endgenerate



generate

    if (USE_MEM_CLK_FOR_ADDR_CMD_CLK == 1)
    begin

        assign ac_clk_2x   = mem_clk_2x;
        assign cs_n_clk_2x = mem_clk_2x;

    end

    else
    begin

        assign ac_clk_2x   = write_clk_2x;
        assign cs_n_clk_2x = write_clk_2x;

    end

endgenerate



//NB. cannot use altddio_out instantiations, as need the combout and regout outputs for mimic path.
generate
genvar clk_pair;

    case ({DDR_MIMIC_PATH_EN, CAPTURE_MIMIC_PATH, DEDICATED_MEMORY_CLK_EN})

    // Mimic path option 1 - this is the default configuration
    default :
    begin

    for (clk_pair = 0 ; clk_pair < MEM_IF_CLK_PAIR_COUNT; clk_pair = clk_pair + 1)
    begin : DDR_CLK_OUT

        // Instance "mem_clk" output pad, with appropriate mimic path connections :
        altddio_bidir   #(
            .extend_oe_disable ("UNUSED"),
            .implement_input_in_lcell ("UNUSED"),
            .intended_device_family ("Cyclone III"),
            .invert_output ("OFF"),
            .lpm_type ("altddio_bidir"),
            .oe_reg ("UNUSED"),
            .power_up_high ("OFF"),
            .width (1)

        )ddr_clk_out_p (
            .padio (mem_clk[clk_pair]),
            .outclock (~mem_clk_2x),
            .inclock (measure_clk_2x),
            .oe (1'b1),
            .datain_h (1'b0),
            .datain_l (1'b1),
            .dataout_h (mimic_data_2x_internal[clk_pair]),
            .dataout_l (),
            .aclr (seq_clk_disable || ctrl_clk_disable[clk_pair]),
            .aset (),
            .combout (),
            .dqsundelayedout (),
            .inclocken (),
            .oe_out (),
            .outclocken (1'b1),
            .sclr (1'b0),
            .sset (1'b0)
        );

        // Instance "mem_clk_n" output pad, no mimic connections made as these are on the
        // 'mem_clk' :
        altddio_bidir   #(
            .extend_oe_disable ("UNUSED"),
            .implement_input_in_lcell ("UNUSED"),
            .intended_device_family ("Cyclone III"),
            .invert_output ("OFF"),
            .lpm_type ("altddio_bidir"),
            .oe_reg ("UNUSED"),
            .power_up_high ("OFF"),
            .width (1)
        )ddr_clk_out_n (
            .padio (mem_clk_n[clk_pair]),
            .outclock (mem_clk_2x),
            .inclock (),
            .oe (1'b1),
            .datain_h (1'b0),
            .datain_l (1'b1),
            .dataout_h (),
            .dataout_l (),
            .aclr (seq_clk_disable || ctrl_clk_disable[clk_pair]),
            .aset (),
            .combout (),
            .dqsundelayedout (),
            .inclocken (),
            .oe_out (),
            .outclocken (1'b1),
            .sclr (1'b0),
            .sset (1'b0)
        );


    end //for

    // Pick off the mimic data from the first internal mimic_data signal :
    assign mimic_data_2x = mimic_data_2x_internal[0];

    end // caseitem

    endcase

endgenerate





// Master reset generation :
always @(posedge ctl_clk or negedge phy_internal_reset_n)
begin

    if (phy_internal_reset_n == 1'b0)
    begin
        reset_master_ams   <= 1'b0;
        global_pre_clear    <= 1'b0;
    end

    else
    begin
        reset_master_ams   <= 1'b1;
        global_pre_clear    <= reset_master_ams;
    end

end


// phy_clk reset generation :
always @(posedge ctl_clk or negedge global_pre_clear)
begin

    if (global_pre_clear == 1'b0)
    begin
        reset_phy_clk_1x_n <= 1'b0;
    end

    else
    begin
        reset_phy_clk_1x_n <= global_pre_clear;
    end

end




// NB. phy_clk reset is generated above.


// phy_clk reset generation for read datapaths :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (2) ) reset_rdp_phy_clk_pipe(
     .clock     (ctl_clk),
     .pre_clear (seq_rdp_reset_req_n && global_pre_clear),
     .reset_out (reset_rdp_phy_clk_1x_n)
);


// mem_clk reset generation :

//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (2) ) mem_pipe (
    .clock     (mem_clk_2x),
    .pre_clear (global_pre_clear),
    .reset_out (mem_reset_n)
);

// ac_clk_2x reset generation :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (2) ) ac_clk_pipe_2x (
    .clock     (ac_clk_2x),
    .pre_clear (global_pre_clear),
    .reset_out (reset_ac_clk_2x_n)
);

// measure_clk_2x reset generation :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (2) ) measure_clk_pipe (
    .clock     (measure_clk_2x),
    .pre_clear (global_pre_clear),
    .reset_out (reset_measure_clk_2x_n)
);

// mem_clk_2x reset generation :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (4) ) mem_clk_pipe(
    .clock     (mem_clk_2x),
    .pre_clear (global_pre_clear),
    .reset_out (reset_mem_clk_2x_n)
);



// resync_clk_2x reset generation :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (2) ) resync_clk_pipe(
    .clock     (resync_clk_2x),
    .pre_clear (seq_rdp_reset_req_n && global_pre_clear),
    .reset_out (reset_resync_clk_2x_n)
);

// write_clk_2x reset generation :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (4) ) write_clk_pipe(
    .clock     (write_clk_2x),
    .pre_clear (global_pre_clear),
    .reset_out (reset_write_clk_2x_n)
);

// cs_clk_2x reset generation :
//
ddr2_phy_alt_mem_phy_reset_pipe # (.PIPE_DEPTH (4) ) cs_n_clk_pipe_2x(
    .clock     (cs_n_clk_2x),
    .pre_clear (global_pre_clear),
    .reset_out (reset_cs_n_clk_2x_n)
);


endmodule
